﻿namespace MobileTrack.Web.Controllers
{
    using System;
    using System.Globalization;
    using System.Linq;
    using System.Net;
    using System.Net.Mail;
    using System.Web.Mvc;
    using System.Web.Security;
    using MobileTrack.Core;
    using MobileTrack.Core.Data;
    using MobileTrack.Web.ViewModels;

    [Authorize(Roles = Constants.AdministradorRole)]
    public class AdminController : BaseController
    {
        private const string ConfirmationEmailBodyTemplate =
@"<html>
<body>
<p>Hola {0}!</p>
<p>Usted ha sido registrado en el sistema <a href=""{2}"">Ribeiro | MobileTrack</a> con las siguientes credenciales:</p>
<ul>
<li>Usuario: <strong>{0}</strong></li>
<li>Contraseña: <strong>{1}</strong></li>
</ul>
<p>Por favor, <a href=""{3}"">inicie sesión</a> en el sistema para activar su cuenta y cambiar la contreña.</p>
</body>
</html>";

        public AdminController(IRepositories repositories, MembershipProvider membershipProvider, RoleProvider roleProvider)
            : base(repositories, membershipProvider, roleProvider)
        {
        }

        public ActionResult ManageUsers()
        {
            return this.View();
        }

        public ActionResult ListUsers(int page, int rows)
        {
            int totalRows = 0;
            page = (page < 1) ? 1 : page;

            var users = this.MembershipProvider
                .GetAllUsers(page - 1, rows, out totalRows)
                .Cast<MembershipUser>()
                .Select(
                    mu => new UserViewModel
                    {
                        UserName = mu.UserName,
                        Email = mu.Email,
                        Role = this.RoleProvider.GetRoleForUser(mu.UserName),
                        Sucursal = this.RoleProvider.GetSucursalRoleForUser(mu.UserName)
                    });

            int totalPages = (totalRows == 0) ? 1 : (int)Math.Ceiling((double)totalRows / (double)rows);

            return this.Json(new { total = totalPages, page = page, records = totalRows, rows = users }, JsonRequestBehavior.AllowGet);
        }

        public ActionResult RegisterUser()
        {
            this.LoadAllRoles();
            this.LoadAllSucursales();

            return this.PartialView("_RegisterUser");
        }

        [HttpPost]
        public ActionResult RegisterUser(UserViewModel model)
        {
            if ((model != null) && this.ModelState.IsValid)
            {
                // Attempt to register the user.
                MembershipCreateStatus createStatus;
                this.MembershipProvider.CreateUser(model.UserName, Constants.DefaultPassword, model.Email, passwordQuestion: null, passwordAnswer: null, isApproved: true, providerUserKey: null, status: out createStatus);

                if (createStatus == MembershipCreateStatus.Success)
                {
                    this.RoleProvider.AddUsersToRoles(
                        new[] { model.UserName },
                        new[] { model.Role, string.Concat(model.Sucursal, Constants.SucursalRoleSuffix) });

                    var profile = MobileTrackProfile.Create(model.UserName);
                    profile.Initialized = false;
                    profile.Save();

                    SendConfirmationEmail(
                        model.Email,
                        model.UserName,
                        Constants.DefaultPassword,
                        this.Url.Action("Index", "Home", null, this.Request.Url.Scheme, this.Request.Url.Host),
                        this.Url.Action("Login", "Account", null, this.Request.Url.Scheme, this.Request.Url.Host));

                    return this.Json(new { Saved = true });
                }
                else
                {
                    this.ModelState.AddModelError(string.Empty, ErrorCodeToString(createStatus));
                }
            }

            // If we got this far, something failed, redisplay form.
            this.LoadAllRoles();
            this.LoadAllSucursales();

            return this.PartialView("_RegisterUser", model);
        }

        public ActionResult EditUser()
        {
            this.LoadAllRoles();
            this.LoadAllSucursales();

            return this.PartialView("_EditUser");
        }

        [HttpPost]
        public ActionResult EditUser(UserViewModel model)
        {
            if ((model != null) && this.ModelState.IsValid)
            {
                this.RoleProvider.RemoveUsersFromRoles(
                    new[] { model.UserName },
                    this.RoleProvider.GetRolesForUser(model.UserName));
                this.RoleProvider.AddUsersToRoles(
                    new[] { model.UserName },
                    new[] { model.Role, string.Concat(model.Sucursal, Constants.SucursalRoleSuffix) });

                return this.Json(new { Saved = true });
            }

            // If we got this far, something failed, redisplay form.
            this.LoadAllRoles();
            this.LoadAllSucursales();

            return this.PartialView("_EditUser", model);
        }

        [HttpPost]
        public ActionResult DeleteUser(string[] userNames)
        {
            if (userNames != null)
            {
                foreach (var userName in userNames)
                {
                    this.MembershipProvider.DeleteUser(userName, true);
                }
            }

            return this.Json(new { Saved = true });
        }

        private static void SendConfirmationEmail(string email, string userName, string password, string homeLink, string loginLink)
        {
            using (var client = new SmtpClient())
            {
                using (var message = new MailMessage())
                {
                    message.From = new MailAddress(((NetworkCredential)client.Credentials).UserName, "Administrador Ribeiro | MobileTrack");
                    message.To.Add(new MailAddress(email));
                    message.Subject = "Usted ha sido registrado en Ribeiro | MobileTrack!";
                    message.IsBodyHtml = true;
                    message.Body = string.Format(
                        CultureInfo.InvariantCulture,
                        ConfirmationEmailBodyTemplate,
                        userName,
                        password,
                        homeLink,
                        loginLink);

                    client.Send(message);
                }
            }
        }

        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://go.microsoft.com/fwlink/?LinkID=177550 for a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "El nombre de usuario ya existe. Por favor, ingrese uno diferente.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "Ya existe un nombre de usuario para la dirección de e-mail seleccionada. Por favor, ingrese una nueva dirección de e-mail.";

                case MembershipCreateStatus.InvalidPassword:
                    return "The password provided is invalid. Please enter a valid password value.";

                case MembershipCreateStatus.InvalidEmail:
                    return "The e-mail address provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "The password retrieval question provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidUserName:
                    return "The user name provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.ProviderError:
                    return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                case MembershipCreateStatus.UserRejected:
                    return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                default:
                    return "Ocurrió un error. Por favor, verifique los datos ingresados e intentelo nuevamente.";
            }
        }

        private void LoadAllRoles()
        {
            this.ViewBag.Roles = this.RoleProvider
                .GetAllRoles()
                .Where(r => !r.EndsWith(Constants.SucursalRoleSuffix, StringComparison.OrdinalIgnoreCase))
                .Select(r => new SelectListItem { Text = r, Value = r });
        }

        private void LoadAllSucursales()
        {
            this.ViewBag.Sucursales = this.Repositories
                .Sucursales
                .All
                .ToArray()
                .Select(
                    s => new SelectListItem
                    {
                        Text = s.DisplayName,
                        Value = s.Nombre
                    });
        }
    }
}